﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace engine
{
    public abstract class Camera
    {
        public Matrix View { get; set; }
        public Matrix Projection { get; set; }

        /// <summary>
        /// View marix properties
        /// </summary>
        public Vector3 Position { get; set; }
        public Vector3 Target { get; set; }
        public Vector3 UpVector { get; set; }
        
        /// <summary>
        /// Projection marix properties
        /// </summary>
        public bool Modified { get; set; }
        public float AspectRatio { get { return aspectRatio; } set { aspectRatio = value; Modified = true; } }
        public float FieldOfView { get { return fieldOfView; } set { fieldOfView = value; Modified = true; } }
        public float FarPlaneDistance { get { return farPlaneDistance; } set { farPlaneDistance = value; Modified = true; } }
        public float NearPlaneDistance { get { return nearPlaneDistance; } set { nearPlaneDistance = value; Modified = true; } }

        private float aspectRatio;
        private float fieldOfView;
        private float farPlaneDistance;
        private float nearPlaneDistance;

        /// <summary>
        /// Camera constructor
        /// </summary>
        /// <param name="Position"></param>
        /// <param name="Target"></param>
        /// <param name="UpVector"></param>
        /// <param name="FieldOfView"></param>
        /// <param name="NearPlaneDistance"></param>
        /// <param name="FarPlaneDistance"></param>
        /// <param name="AspectRatio"></param>
        public Camera(Vector3 Position, Vector3 Target, Vector3 UpVector,
            float FieldOfView, float NearPlaneDistance, float FarPlaneDistance, float AspectRatio)
        {
            this.Position = Position;
            this.Target = Target;
            this.UpVector = UpVector;
            this.FieldOfView = FieldOfView;
            this.NearPlaneDistance = NearPlaneDistance;
            this.FarPlaneDistance = FarPlaneDistance;
            this.AspectRatio = AspectRatio;

            this.Position.Normalize();
            this.Target.Normalize();

            this.Modified = false;

            // Create view and projection
            View = Matrix.CreateLookAt(Position, Target, UpVector);
            UpdateProjectionMatrix();
        }

        public virtual void Update()
        {
        }

        private void UpdateProjectionMatrix()
        {
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(FieldOfView),
                AspectRatio, NearPlaneDistance, FarPlaneDistance);
            Modified = false;
        }

        /// <summary>
        /// This is where view matrix is updated
        /// </summary>
        protected void UpdateViewMatrix()
        {
            View = Matrix.CreateLookAt(Position, Target, UpVector);

            if (Modified == true)
            {
                UpdateProjectionMatrix();
            }
        }
    }
}
